package com.pata.display
{
	import com.pata.enum.InvalidationType;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;

	/**
	 * @data		2011-4-6	
	 * @author	pata
	 */
	public class AbstractDisplay extends Sprite implements IDisplay
	{
		protected var mRegisterListeners:Array = [];
		protected var mX:Number = 0;
		protected var mY:Number = 0;
		protected var mWidth:Number = 0;
		protected var mHeight:Number = 0;
		protected var mInvalidHash:Object = null;
		public override function get x():Number
		{
			mX = (mX > super.x ? mX : super.x);
			return mX;
		}
		public override function set x(value:Number):void
		{
			if(mX === value) return;
			move(mX, mY);
		}
		
		public override function get y():Number
		{
			mY = (mY > super.y ? mY : super.y);
			return mY;
		}
		
		public override function set y(value:Number):void
		{
			if(mY === value) return;
			move(mX, mY);
		}
		
		public override function get width():Number
		{
			mWidth = ( mWidth > super.width ? mWidth : super.width);
			return mWidth;
		}
		
		public override function set width(value:Number):void
		{
			if(mWidth === value) return;
			resize(mWidth, mHeight);
		}
		
		public override function get height():Number
		{
			mHeight = (mHeight > super.height ? mHeight : super.height);
			return mHeight;
		}
		public override function set height(value:Number):void
		{
			if(mHeight === value) return;			
			resize(mWidth, mHeight);
		}
		
		public function get bitmapData():BitmapData
		{
			var bitmapData:BitmapData = new BitmapData(mWidth, mHeight);
			bitmapData.draw( this );
			return bitmapData;
		}
		
		public function AbstractDisplay(self:AbstractDisplay)
		{
			if(self != this)
			{
				throw new Error("AbstrctDisplay 不可实例化");
			}else
			{
				mInvalidHash = {};
				addStageListeners();
			}
		}
		
		private function addStageListeners():void
		{
			this.$addEventListener(Event.ADDED_TO_STAGE, onStageAdded, false, 0, true);
			this.$addEventListener(Event.REMOVED_FROM_STAGE, onStageRemoved, false, 0, true);
			configUI();
		}
		
		protected function onStageRemoved(e:Event):void
		{
			this.$removeEventListener(Event.ADDED_TO_STAGE, onStageAdded);
			this.$removeEventListener(Event.REMOVED_FROM_STAGE, onStageRemoved);
			this.destroy();
		}
		
		protected function onStageAdded(e:Event):void
		{
			invalidate();
		}
		
		protected function invalidate(property:String = InvalidationType.ALL, calllater:Boolean = true):void
		{
			mInvalidHash[ property ] = true;
			if(calllater) 
				addEventListener(Event.ENTER_FRAME, onInvalidate);
			else 
				draw();
		}
		/*public function invalidateNow():void
		{
			invalidate( InvalidationType.ALL, false);
		}*/
		private function onInvalidate(e:Event):void
		{
			draw();
			removeEventListener(Event.ENTER_FRAME, onInvalidate);
		}
		
		protected function isInvalid(property:String, ...properties:Array):Boolean
		{
			if(mInvalidHash[property] || mInvalidHash[InvalidationType.ALL]) { return true; }
			while(properties.length > 0)
			{
				if(mInvalidHash[properties.pop()])
					return true;
			}
			return false;
		}
		public function move(newX:Number, newY:Number):void
		{
			mX = newX;
			mY = newY;
			super.x = newX;
			super.y = newY;
		}
		public function resize(w:Number, h:Number):void
		{
			mWidth = w;
			mHeight = h;
			super.width = mWidth;
			super.height = mHeight;
			this.invalidate( InvalidationType.SIZE );
		}		
		
		protected function setStyle(style:String, value:Object):void
		{
			isInvalid( InvalidationType.STYLES );
		}
		
		protected function configUI():void { };
		public function draw():void { mInvalidHash = {}; };
		
		public function destroy():void
		{
			var num:int = this.numChildren;
			while(num > 0){
				this.removeChildAt(0);
			}
			
			this.clearEventListeners();
		}
		
		public function clearEventListeners():void
		{
			var type:String;
			for(type in mRegisterListeners)
			{
				if(hasEventListener(type))
				{
					this.removeEventListener(type, mRegisterListeners[ type ]);
				}
			}
			mRegisterListeners = null;
		}
		protected function $addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
		{
			super.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}
		
		override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
		{
			this.$addEventListener(type, listener, useCapture, priority, useWeakReference);
			mRegisterListeners[ type ] = listener;
		}
		
		protected function $removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
		{
			super.removeEventListener(type, listener, useCapture);
		}
		
		override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
		{
			this.$removeEventListener(type, listener, useCapture);
			if(mRegisterListeners[ type ])
				delete mRegisterListeners[ type ];
		}
	}
}